// HD44780 Controller instruction set http://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller
// Si RS OFF -> Commande, SI RS ON -> Donnee

// 4-bit Initialization:
// ! Valable si pin R/W force a 0 par cablage materiel
// LCD Control Pins
#include "stm32f4xx.h"
#include "commands_4bits.h"

#define E_ON    GPIOC->BSRRL = 1<<1
#define E_OFF   GPIOC->BSRRH = 1<<1
#define RS_ON   GPIOC->BSRRL = 1<<2
#define RS_OFF  GPIOC->BSRRH = 1<<2
// LCD Pins
#define LCD_DATA_PORT GPIOB
#define P4 11
#define P5 12
#define P6 13
#define P7 14
#define P4_ON   GPIOB->BSRRL = 1<<11
#define P5_ON   GPIOB->BSRRL = 1<<12
#define P6_ON   GPIOB->BSRRL = 1<<13
#define P7_ON   GPIOB->BSRRL = 1<<14
#define P4_OFF  GPIOB->BSRRH = 1<<11
#define P5_OFF  GPIOB->BSRRH = 1<<12
#define P6_OFF  GPIOB->BSRRH = 1<<13
#define P7_OFF  GPIOB->BSRRH = 1<<14

#define bit7 1<<7
#define bit6 1<<6
#define bit5 1<<5
#define bit4 1<<4

// Ecrit 1 caractere
void write_char(char car)
{
        RS_ON;  // donnee
        E_ON;           // arme
        if ( car & bit7 )
          P7_ON;
        else
                P7_OFF;
        if ( car & bit6 )
          P6_ON;
        else
                P6_OFF;
        if ( car & bit5 )
          P5_ON;
        else
                P5_OFF;
        if ( car & bit4 )
          P4_ON;
        else
                P4_OFF;
        E_OFF;  // valide commande sur front descendant
        car = car<<4;
        E_ON;   // arme
        if ( car & bit7 )
          P7_ON;
        else
                P7_OFF;
        if ( car & bit6 )
          P6_ON;
        else
                P6_OFF;
        if ( car & bit5 )
          P5_ON;
        else
                P5_OFF;
        if ( car & bit4 )
          P4_ON;
        else
                P4_OFF;
        E_OFF;  // valide commande sur front descendant
        Delay(10000);    // 37 [us]
}
// CHANGE L'ADRESSE DDRAM
// 2x16 -> ligne 1 commence a 0x00, ligne 2 commence a 0x40
// 4 lignes: 0x00, 0x40, 0x14, 0x54  (a verifier)
void line_feed()
{
        RS_OFF; // Commande
        E_ON;           // arme
        P7_ON;
        P6_ON;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(100000); // 37 us       E_ON;   // arme
  E_ON;         // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF; // front descendant -> valide commande
        Delay(100000);   // 37 [us]
}

void lcd_init()
{
  function_set();
  entry_mode_set();
  display_on_off_control();
        //cursor_display_shift();
        //clear_display();
}
// CURSOR & DISPLAY SHIFTS : direction deplacement curseur et affichage
void cursor_display_shift(void)
{
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_ON;  // commande Cursor/Display Shift
        E_OFF;  // valide commande sur front descendant
        //Delay(100000); // 37 us       E_ON;
  E_ON;         // arme
        P7_OFF; // Cursor-move or Display-shift: OFF = Move cursor, ON = shift display
        P6_OFF; // Shift Direction: OFF = Shift Left, ON = Shift Right
        P5_OFF; // n/a
        P4_OFF; // n/a
        E_OFF; // front descendant -> valide commande
        Delay(100000);   // 37 [us]
}
// ENTRY MODE SET : direction deplacement curseur et du shift du display pendant ecriture/lecture donnee
void entry_mode_set(void)
{
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(100000); // 37 us
        E_ON;   // arme
        P7_OFF;
        P6_ON;  // commande Entry Mode Set (effet si P5 ON & P4 OFF ou P5 OFF & P4 ON)
        P5_ON;  // Cursor Move Direction, OFF = decremente position curseur, ON = incremente position curseur
        P4_OFF; // Display Shift, OFF = pas de shift du display, ON = shift du display
        E_OFF; // front descendant -> valide commande
        Delay(100000);   // 37 [us]
}
// FUNCTION SET: longueur de donnees pour l'interface, nombre de lignes, fonte caracteres
void function_set(void)
{
        // DATA INTERFACE LENGTH = 4 bits -> il faut envoyer 0x28 0b00101000 -> on envoie 0010, puis 1000 decale de 4
        RS_OFF; // commande
        E_ON;           // arme pour bits poids fort
        P7_OFF;
        P6_OFF;
        P5_ON;  // Commande Function Set
        P4_OFF; // Interface 4 bits
        E_OFF;  // valide commande sur front descendant
        //Delay(100000); // 37 us
        E_ON;   // arme pour bits poifs faible
        P7_ON;  // 2 lignes
        P6_OFF; // OFF = 5x7 dots, ON = 5x10 dots, ! si ON 5x10 empiete sur la ligne en-dessous
        P5_OFF; // n/a
        P4_OFF; // n/a
        E_OFF; // front descendant -> valide commande
        Delay(100000);   // 37 [us]
}
// DISPLAY CONTROL
void display_on_off_control()
{
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(100000); // 37 us
        E_ON;   // arme
        P7_ON;  // Commande Display Control
        P6_ON;  // ON = display ON, OFF = display OFF
        P5_ON;  // ON = cursor ON, OFF = cursor OFF
        P4_ON;  // ON = cursor blink, OFF = no blink, juste souligne fixe
        E_OFF; // front descendant -> valide commande
        Delay(100000);   // 37 [us]
}
// CURSOR HOME (pas d'effacement de l'afficheur)
void cursor_home(void)
{
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(10000);
        E_ON;   // arme
        P7_OFF;
        P6_OFF;
        P5_ON;  // commande Cursor Home
        P4_OFF; // n/a
        E_OFF; // front descendant -> valide commande
        Delay(1000000);  // ! 1.52 [ms]
}
// CLEAR DISPLAY (efface afficheur et retour home = adresse 0)
void clear_display(void)
{
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(10000);
        E_ON;   // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_ON; // commande Clear Cisplay
        E_OFF; // front descendant -> valide commande
        Delay(1000000);  // ! 1.52 [ms]
}
void Delay(int d)
{
        int i;
        for(i=0; i < d; i++)
        ;
}


void init_old(void)
{
        // DATA INTERFACE LENGTH = 4 bits
        // il faut envoyer 0x28 0b00101000
        // -> on envoie 0010, puis 1000 decale de 4
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_ON;
        P4_OFF; // 4 bits
        E_OFF;  // valide commande sur front descendant
        //Delay(10000);
        E_ON;   // arme
        P7_ON;  // 2 lignes
        P6_OFF; // 5x7 dots
        P5_OFF; // n/a
        P4_OFF; // n/a
        E_OFF; // front descendant -> valide commande
        Delay(100000);

        // CLEAR DISPLAY
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // envoie commande sur front descendant
        //Delay(10000);
        E_ON;   // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_ON;
        E_OFF; // front descendant -> envoie
        Delay(10000000);

                // ENTRY MODE SET
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // valide commande sur front descendant
        //Delay(10000); // 37 us
        E_ON;   // arme
        P7_OFF;
        P6_OFF;  // commande Entry Mode Set
        P5_ON;  // Cursor Move Direction, OFF = decremente position curseur, ON = incremente position curseur
        P4_OFF; // Display Shift, OFF = pas de shift du display, ON = shift du display
        E_OFF; // front descendant -> valide commande
        Delay(1000000);  // 37 [us]

        // DISPLAY AND CURSOR CONTROL
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // envoie commande sur front descendant
//      Delay(10000);
        E_ON;   // arme
        P7_ON;  // DISPLAY AND CURSOR CONTROL
        P6_ON;  // Display ON
        P5_ON;  //
        P4_ON;  // ON = cursor clignote, OFF = pas de cursor
        E_OFF; // front descendant -> envoie
        Delay(100000);

/*
        // CLEAR DISPLAY
        RS_OFF; // commande
        E_ON;           // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_OFF;
        E_OFF;  // envoie commande sur front descendant
        Delay(10000);
        E_ON;   // arme
        P7_OFF;
        P6_OFF;
        P5_OFF;
        P4_ON;
        E_OFF; // front descendant -> envoie
        Delay(100000);
        */
}


